<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<title>Chat Example</title>
<script type="text/javascript">
/**
 * 计算字符串所占的内存字节数，默认使用UTF-8的编码方式计算，也可制定为UTF-16
 * UTF-8 是一种可变长度的 Unicode 编码格式，使用一至四个字节为每个字符编码
 *
 * 000000 - 00007F(128个代码)      0zzzzzzz(00-7F)                             一个字节
 * 000080 - 0007FF(1920个代码)     110yyyyy(C0-DF) 10zzzzzz(80-BF)             两个字节
 * 000800 - 00D7FF
   00E000 - 00FFFF(61440个代码)    1110xxxx(E0-EF) 10yyyyyy 10zzzzzz           三个字节
 * 010000 - 10FFFF(1048576个代码)  11110www(F0-F7) 10xxxxxx 10yyyyyy 10zzzzzz  四个字节
 *
 * 注: Unicode在范围 D800-DFFF 中不存在任何字符
 * {@link http://zh.wikipedia.org/wiki/UTF-8}
 *
 * UTF-16 大部分使用两个字节编码，编码超出 65535 的使用四个字节
 * 000000 - 00FFFF  两个字节
 * 010000 - 10FFFF  四个字节
 *
 * {@link http://zh.wikipedia.org/wiki/UTF-16}
 * @param  {String} str
 * @param  {String} charset utf-8, utf-16
 * @return {Number}
 */
var sizeof = function(str, charset = 'utf-8'){
    var total = 0,
        charCode,
        i,
        len;
    charset = charset ? charset.toLowerCase() : '';
    if(charset === 'utf-16' || charset === 'utf16'){
        for(i = 0, len = str.length; i < len; i++){
            charCode = str.charCodeAt(i);
            if(charCode <= 0xffff){
                total += 2;
            }else{
                total += 4;
            }
        }
    }else{
        for(i = 0, len = str.length; i < len; i++){
            charCode = str.charCodeAt(i);
            if(charCode <= 0x007f) {
                total += 1;
            }else if(charCode <= 0x07ff){
                total += 2;
            }else if(charCode <= 0xffff){
                total += 3;
            }else{
                total += 4;
            }
        }
    }
    return total;
}
function formatMsg(str) {
    let reg=/点击(\[[^\]]*\])查看表情/g;
    let res = str.match(reg);
    res && res.forEach(item=>{
        let url = item.replace('点击[','').replace(']查看表情','');
        str = str.replace(item,`<img class="pic" src="${url}"/>`);
    })
    console.log(str);
    return str;
}
function chooseUser(uid) {
    if(to.value == uid){
        to.value = '';
    }else{
        to.value = uid;
    }
    selectedCurrent();
}

function selectedCurrent() {
    let ulist = document.querySelectorAll("#idlist li");
    ulist.forEach(item=>{
        if(item.dataset.id == to.value){
            item.style.color = 'red';
        }else{
            item.style.color = 'black';
        }
    })
}

window.onload = function () {
    var conn;
    var msg = document.getElementById("msg");
    var log = document.getElementById("log");
    var nickname = document.getElementById("nickname");
    var to = document.getElementById("to");
    var myid = document.getElementById("myid");
    var idlist = document.getElementById("idlist");

    function appendLog(item) {        
        var doScroll = log.scrollTop > log.scrollHeight - log.clientHeight - 1;
        log.appendChild(item);
        if (doScroll) {
            log.scrollTop = log.scrollHeight - log.clientHeight;
        }
    }

    document.getElementById("form").onsubmit = function () {
        if (!conn) {
            return false;
        }
        if (!msg.value) {
            return false;
        }
        let msgval = nickname.value + ': ' + msg.value;
        let msgObj = {from:myid.value,msg:msgval,type:"broadcast",to:""};
        console.log(msgObj);
        if(to.value){
            msgObj.to = to.value;
            msgObj.type = "say";
        }
        let msgstr = JSON.stringify(msgObj);
        let msgsize = sizeof(msgstr);
        console.log(msgsize);
        if(msgsize>4096){
            alert('发送内容过长');
            return false;
        }
        conn.send(msgstr);
        msg.value = "";
        return false;
    };

    if (window["WebSocket"]) {
        conn = new WebSocket("ws://" + document.location.host + "/ws");
        conn.onclose = function (evt) {
            var item = document.createElement("div");
            item.innerHTML = "<b>Connection closed.</b>";
            appendLog(item);
        };
        conn.onmessage = function (evt) {
            console.log(evt.data);
            var messages = evt.data.split('\n');
            console.log(messages);
            for (var i = 0; i < messages.length; i++) {
                if(!messages[i]){
                    continue;
                }
                let obj = JSON.parse(messages[i]);
                console.log(obj);
                if(obj.type == 'broadcast' || obj.type == 'say'){
                    var item = document.createElement("div");
                    item.innerHTML = formatMsg(obj.msg);
                    appendLog(item);
                }else if(obj.type == 'login'){
                    let arr = obj.msg.split("_");
                    myid.value = arr[0];
                    nickname.value = arr[1];
                }else if(obj.type == 'list'){
                    let arr = obj.msg.split(",");
                    let str2 = '';
                    let findto = false;
                    arr.forEach((str)=>{
                        if(!str){
                            return;
                        }
                        let str_arr = str.split('_');
                        if(to.value == str_arr[0]){
                            findto = true;
                        }
                        if(str_arr[0]!= myid.value){                            
                            str2 +=`<li data-id="${str_arr[0]}" onclick="chooseUser('${str_arr[0]}')">${str_arr[1]}</li>`;
                        }
                    })
                    if(!findto){
                        to.value = '';
                    }
                    idlist.innerHTML = str2;
                    selectedCurrent();
                }                  
            }
        };
    } else {
        var item = document.createElement("div");
        item.innerHTML = "<b>Your browser does not support WebSockets.</b>";
        appendLog(item);
    }
};
</script>
<style type="text/css">
html {
    overflow: hidden;
}

body {
    overflow: hidden;
    padding: 0;
    margin: 0;
    width: 100%;
    height: 100%;
    background: gray;
}

#log {
    background: white;
    margin: 0;
    padding: 0.5em 0.5em 0.5em 0.5em;
    position: absolute;
    top: 0.5em;
    left: 0.5em;
    right: 0.5em;
    bottom: 3em;
    overflow: auto;
}

#nickname{
    position: absolute;
    z-index: 666;
    top: 20px;
    right: 20px;
}

#to{
    position: absolute;
    z-index: 666;
    top: 80px;
    right: 20px;
}

#myid{
    position: absolute;
    z-index: 666;
    top: 140px;
    right: 20px;
}

#idlist{
    position: absolute;
    z-index: 666;
    top: 200px;
    right: 20px;
}

#form {
    padding: 0 0.5em 0 0.5em;
    margin: 0;
    position: absolute;
    bottom: 1em;
    left: 0px;
    width: 100%;
    overflow: hidden;
}

</style>
</head>
<body>
<div id="log"></div>
<input type="text" id="nickname" placeholder="请输入昵称" value="匿名" />
<input type="text" id="myid" placeholder="myid" />
<input type="text" id="to" placeholder="私聊的用户指针" />
<ul id="idlist">
   
</ul>
<form id="form">
    <input type="submit" value="Send" />
    <input type="text" id="msg" size="64" autofocus style="width:80%;" />
</form>
</body>
</html>